package com.example.trackcircuitdiagnosis.time;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.example.trackcircuitdiagnosis.dto.DemoDataDTO;
import com.example.trackcircuitdiagnosis.dto.KGLDTO;
import com.example.trackcircuitdiagnosis.dto.KGLresDTO;
import com.example.trackcircuitdiagnosis.dto.KGLretryDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 从Excel中获取开关量数据的组件
 */


//SELECT
//	t.* ,c.device_name,c.position_name,c.did
//FROM
//	t_app_changekglvalue1 AS t left join changekgl as c on t.FADCODE=c.id
//WHERE
//	t.FADCODE IN (
//	SELECT
//		id AS FADCODE
//	FROM
//		`changekgl`
//	WHERE
//		id >= 2008
//	AND ( position_name = '-XGJ' OR position_name = '-QGJ' ))
//ORDER BY
//	t.FADCODE,
//	t.FDATE;
@Component
public class GetKglDataFromExcel {
    

    /**
     * 读取Excel中的KGL数据并处理
     *
     * @return KGL数据的列表的列表
     * @throws JsonProcessingException JSON处理异常
     */
    public List<List<KGLresDTO>> readKGL() throws JsonProcessingException {
        // 用于存储KGL数据的列表
        List<KGLDTO> kglList = new ArrayList<>();

        // 从Excel文件获取输入流
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("excel/查找开关量.xlsx");

        // 使用EasyExcel读取KGL数据
        EasyExcel.read(inputStream, KGLDTO.class, new PageReadListener<KGLDTO>(list -> {
            if (!list.isEmpty()) {
                // 将KGL数据添加到kglList中
                kglList.addAll(list);
            }
        })).headRowNumber(1).autoCloseStream(false).sheet().doRead();

        // 按FADCODE分组并排序KGL数据
        Map<String, List<KGLDTO>> groupedAndSorted = groupAndSortByFADCODE(kglList);

        // 重试KGL数据并创建KGLretryDTO对象列表
        List<KGLretryDTO> kgLretries = groupedAndSorted.values().stream()
                .map(value -> {
                    KGLretryDTO kgLretry = new KGLretryDTO();
                    kgLretry.setKgl(retry(value));
                    kgLretry.setPositionName(value.get(0).getPositionName());
                    kgLretry.setDeviceName(value.get(0).getDeviceName());
                    kgLretry.setDid(value.get(0).getDid());
                    return kgLretry;
                })
                .collect(Collectors.toList());

        // 处理KGL重试并创建KGLresDTO对象列表的列表
        return handleKGL(kgLretries);
    }

    /**
     * 按FADCODE分组并排序KGL数据
     *
     * @param kglList KGL数据列表
     * @return 分组并排序后的KGL数据Map
     */
    public Map<String, List<KGLDTO>> groupAndSortByFADCODE(List<KGLDTO> kglList) {
        // 按FADCODE分组并按FDATE字段对每个分组内的元素进行排序
        return kglList.stream()
                .collect(Collectors.groupingBy(KGLDTO::getFADCODE, HashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.stream()
                                        .sorted(Comparator.comparing(KGLDTO::getFDATE))
                                        .collect(Collectors.toList())
                        )
                ));
    }

    /**
     * 重试处理原始KGL数据
     *
     * @param rawData 原始KGL数据列表
     * @return 处理后的KGL数据数组
     */
    public byte[] retry(List<KGLDTO> rawData) {
        // 用于存储KGL数据的数组
        byte[] arr = new byte[86401];
        // 用-1填充数组
        Arrays.fill(arr, (byte) -1);

        if (!rawData.isEmpty()) {
            // 根据第一个数据条目设置数组中的初始值
            int initialValue = Integer.parseInt(rawData.get(0).getFVALUE());
            arr[0] = (byte) (initialValue == 1 ? 0 : 1);
        }

        // 使用FDATE和FVALUE填充数组
        for (KGLDTO data : rawData) {
            int index = calculatorSecond(data.getFDATE());
            byte value = Byte.parseByte(data.getFVALUE());
            arr[index] = value;
        }

        // 用前一个非空值替换-1值
        byte temp = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] != -1) {
                temp = arr[i];
            } else {
                arr[i] = temp;
            }
        }

        return arr;
    }

    /**
     * 计算给定日期字符串的秒数
     *
     * @param dateString 日期字符串
     * @return 秒数
     */
    public int calculatorSecond(String dateString) {
        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

        // 将字符串日期解析成LocalDateTime对象
        LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);

        // 获取当天零点的时间
        LocalDateTime midnight = LocalDateTime.of(dateTime.toLocalDate(), LocalTime.from(LocalDateTime.MIN));

        // 计算与当天零点的时间差，单位为秒
        return (int) ChronoUnit.SECONDS.between(midnight, dateTime);
    }

    /**
     * 处理KGL重试并创建KGLresDTO对象列表的列表
     *
     * @param kgLretries KGLretryDTO对象列表
     * @return KGLresDTO对象列表的列表
     * @throws JsonProcessingException JSON处理异常
     */
    public List<List<KGLresDTO>> handleKGL(List<KGLretryDTO> kgLretries) throws JsonProcessingException {
        List<List<KGLresDTO>> list = new ArrayList<>();
        // 遍历一天中的每一秒
        for (int i = 0; i < 86400; i++) {
            int finalI = i;
            // 将KGLretryDTO对象映射为KGLresDTO对象
            List<KGLresDTO> result = kgLretries.parallelStream()
                    .map(kgLretry -> {
                        byte value = kgLretry.getKgl()[finalI];
                        int did = kgLretry.getDid();
                        String deviceName = kgLretry.getDeviceName();
                        String positionName = kgLretry.getPositionName();
                        KGLresDTO kgLres = new KGLresDTO();
                        kgLres.setDid(did);
                        kgLres.setPositionName(positionName);
                        kgLres.setDeviceName(deviceName);
                        kgLres.setValue(value);
                        return kgLres;
                    })
                    .collect(Collectors.toList());
            list.add(result);
        }
        return list;
    }
}
